package com.tqz.rc.spring.cloud.ribbon.rule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import com.tqz.rc.api.Instance;
import com.tqz.rc.client.naming.NamingService;
import com.tqz.rc.common.exception.RcException;
import com.tqz.rc.spring.cloud.TqzRcProperties;
import com.tqz.rc.spring.cloud.TqzRcServiceManager;
import com.tqz.rc.spring.cloud.ribbon.TqzRcServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>同一个集群优先调用策略。
 * 如果当前服务所在集群不存在，会调用其他集群的实例，如果还是不存在，那就无能为力了。
 *
 * @author tianqingzhao
 * @since 2021/9/29 15:51
 */
public class TqzRcTheSameClusterPriorityRule extends AbstractLoadBalancerRule {

    private static final Logger log = LoggerFactory.getLogger(TqzRcTheSameClusterPriorityRule.class);

    private TqzRcServiceManager serviceManager;

    private TqzRcProperties properties;

    public TqzRcTheSameClusterPriorityRule(TqzRcServiceManager serviceManager, TqzRcProperties properties) {
        this.serviceManager = serviceManager;
        this.properties = properties;
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {

    }

    @Override
    public Server choose(Object key) {
        try {
            // 第一步:获取当前服务所在的集群
            String currentClusterName = properties.getClusterName();

            // 第二步:获取一个负载均衡对象
            BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) getLoadBalancer();

            // 第三步:获取当前调用的微服务的名称
            String invokedSerivceName = baseLoadBalancer.getName();

            // 第四步:获取nacos clinet的服务注册发现组件的api
            NamingService namingService = serviceManager.getNamingService(properties.getTqzRcProperties());

            // 第五步:获取所有的服务实例
            List<Instance> allInstance = namingService.selectInstances(invokedSerivceName);

            List<Instance> theSameClusterNameInstList = new ArrayList<>();

            //第六步:过滤筛选同集群下的所有实例
            for (Instance instance : allInstance) {
                if (StringUtils.endsWithIgnoreCase(instance.getClusterName(), currentClusterName)) {
                    theSameClusterNameInstList.add(instance);
                }
            }

            Instance toBeChooseInstance;

            //第七步:选择合适的一个实例调用
            if (theSameClusterNameInstList.isEmpty()) {

                toBeChooseInstance = TqzRcWeightedBalancer.chooseInstanceByRandomWeight(allInstance);

                log.info("发生跨集群调用--->当前微服务所在集群:{},被调用微服务所在集群:{},Host:{},Port:{}",
                        currentClusterName, toBeChooseInstance.getClusterName(), toBeChooseInstance.getIp(), toBeChooseInstance.getPort());
            } else {
                toBeChooseInstance = TqzRcWeightedBalancer.chooseInstanceByRandomWeight(theSameClusterNameInstList);

                log.info("同集群调用--->当前微服务所在集群:{},被调用微服务所在集群:{},Host:{},Port:{}",
                        currentClusterName, toBeChooseInstance.getClusterName(), toBeChooseInstance.getIp(), toBeChooseInstance.getPort());
            }

            return new TqzRcServer(toBeChooseInstance);

        } catch (RcException e) {
            log.error("同集群优先权重负载均衡算法选择异常:{}", e);
        }
        return null;
    }
}
